import Recorder from 'js-audio-recorder';
import { getLocale } from 'locales';
import { useCallback, useEffect, useRef, useState } from 'react';
import { toast } from 'react-hot-toast';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';

import HighlightOffOutlinedIcon from '@mui/icons-material/HighlightOffOutlined';
import KeyboardVoiceIcon from '@mui/icons-material/KeyboardVoice';
import StopCircleOutlinedIcon from '@mui/icons-material/StopCircleOutlined';
import SendIcon from '@mui/icons-material/Telegram';
import TuneIcon from '@mui/icons-material/Tune';
import { CircularProgress, IconButton, TextField } from '@mui/material';
import InputAdornment from '@mui/material/InputAdornment';

import {
  askUserState,
  chatSettingsState,
  loadingState,
  sessionState
} from 'state/chat';
import { chatHistoryState } from 'state/chatHistory';
import { clientState } from 'state/client';
import { localeState } from 'state/project';

import HistoryButton from '../history';

interface Props {
  onSubmit: (message: string) => void;
  onReply: (message: string) => void;
}

function getLineCount(el: HTMLDivElement) {
  const textarea = el.querySelector('textarea');
  if (!textarea) {
    return 0;
  }
  const lines = textarea.value.split('\n');
  return lines.length;
}
let recorder: any = null;
let oCanvas: any = null;
let ctx: any = null;
let drawRecordId: any = null;
const MAX_RECORD_TIME = 30; // 录音最长时间30秒
const Input = ({ onSubmit, onReply }: Props) => {
  const ref = useRef<HTMLDivElement>(null);
  const setChatHistory = useSetRecoilState(chatHistoryState);
  const [chatSettings, setChatSettings] = useRecoilState(chatSettingsState);
  const [locale] = useRecoilState(localeState);
  const loading = useRecoilValue(loadingState);
  const askUser = useRecoilValue(askUserState);
  const session = useRecoilValue(sessionState);
  const [value, setValue] = useState('');
  const [isComposing, setIsComposing] = useState(false);

  const [sampleBit] = useState(16);
  const [sampleRate] = useState(16000);
  const [numChannel] = useState(1);
  const [compiling] = useState(false);
  const [isRecording, setIsRecording] = useState(false);
  const [duration, setDuration] = useState<number | string>(0);
  const [tranAudioLoading, setTranAudioLoading] = useState<boolean>(false);
  const socketOk = session?.socket && !session?.error;
  const disabled = !socketOk || loading || askUser?.spec.type === 'file';
  const client = useRecoilValue(clientState);

  useEffect(() => {
    if (ref.current && !loading && !disabled) {
      ref.current.focus();
    }
  }, [loading, disabled]);

  const submit = useCallback(() => {
    if (value === '' || disabled) {
      return;
    }
    if (askUser) {
      onReply(value);
    } else {
      onSubmit(value);
    }
    setValue('');
  }, [value, disabled, setValue, askUser, onSubmit]);

  const handleCompositionStart = () => {
    setIsComposing(true);
  };

  const handleCompositionEnd = () => {
    setIsComposing(false);
  };

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      if (e.key === 'Enter' && !e.shiftKey) {
        if (!isComposing) {
          e.preventDefault();
          submit();
        }
      } else if (e.key === 'ArrowUp') {
        const lineCount = getLineCount(e.currentTarget as HTMLDivElement);
        if (lineCount <= 1) {
          setChatHistory((old) => ({ ...old, open: true }));
        }
      }
    },
    [submit, setChatHistory, isComposing]
  );

  const onHistoryClick = useCallback((content: string) => {
    if (ref.current) {
      setValue(content);
    }
  }, []);

  const tranRecordToText = (form: any) => {
    client
      .getSpeechToText(form)
      .then((res) => {
        setValue(res.data);
        setTranAudioLoading(false);
        setIsRecording(false);
      })
      .catch((err) => {
        console.log(err, 'error');
      });
  };

  const collectData = () => {
    return {
      sampleBits: sampleBit,
      sampleRate,
      numChannels: numChannel,
      compiling // 是否开启边录音边转化（后期改用web worker）
    };
  };

  const stopDrawPlay = () => {
    // drawPlayId && cancelAnimationFrame(drawPlayId);
    // drawPlayId = null;
  };

  const drawRecord = () => {
    // 用requestAnimationFrame稳定60fps绘制
    drawRecordId = requestAnimationFrame(drawRecord);
    // 实时获取音频大小数据
    const dataArray = recorder.getRecordAnalyseData(),
      bufferLength = dataArray.length;
    // 填充背景色
    ctx.fillStyle = 'rgb(245 248 255)';
    ctx.fillRect(0, 0, oCanvas.width, oCanvas.height);
    // 设定波形绘制颜色
    ctx.lineWidth = 2;
    ctx.strokeStyle = 'rgb(27 92 243)';
    ctx.beginPath();
    const sliceWidth = (oCanvas.width * 1.0) / bufferLength; // 一个点占多少位置，共有bufferLength个点要绘制
    let x = 0; // 绘制点的x轴位置
    for (let i = 0; i < bufferLength; i++) {
      const v = dataArray[i] / 128.0;
      const y = (v * oCanvas.height) / 2;

      if (i === 0) {
        // 第一个点
        ctx.moveTo(x, y);
      } else {
        // 剩余的点
        ctx.lineTo(x, y);
      }
      // 依次平移，绘制所有点
      x += sliceWidth;
    }
    ctx.lineTo(oCanvas.width, oCanvas.height / 2);
    ctx.stroke();
  };

  const downloadWAV = () => {
    if (recorder) {
      //转成File类型
      setTranAudioLoading(true);
      const audioFile = new File([recorder.getWAVBlob()], 'test.wav', {
        type: 'audio/wav'
      });
      const formData = new FormData();
      formData.append('file', audioFile, 'test.wav');
      tranRecordToText(formData);
      // 下载文件
      // recorder.downloadWAV();
    }
  };

  const endRecord = () => {
    recorder && recorder.stop();
    drawRecordId && cancelAnimationFrame(drawRecordId);
    drawRecordId = null;
    downloadWAV();
    clearPlay();
  };

  const clearPlay = () => {
    if (recorder) {
      recorder.destroy().then(() => {
        recorder = null;
      });
    }
    if (drawRecordId) {
      cancelAnimationFrame(drawRecordId);
      drawRecordId = null;
    }
  };

  const startRecordAudio = () => {
    clearPlay();
    const config = collectData();
    if (!recorder) {
      recorder = new Recorder(config);
      recorder.onprogress = (params: any) => {
        //控制录音时长为30秒
        if (params.duration > MAX_RECORD_TIME) {
          endRecord();
        }
        tranRecordSecToMin(parseInt(params.duration));
        // 此处控制数据的收集频率
        if (config.compiling) {
          console.log('音频总数据：', params.data);
        }
      };
      recorder.onplay = () => {
        console.log('%c回调监听，开始播放音频', 'color: #2196f3');
      };
      recorder.onpauseplay = () => {
        console.log('%c回调监听，暂停播放音频', 'color: #2196f3');
      };
      recorder.onresumeplay = () => {
        console.log('%c回调监听，恢复播放音频', 'color: #2196f3');
      };
      recorder.onstopplay = () => {
        console.log('%c回调监听，停止播放音频', 'color: #2196f3');
      };
      recorder.onplayend = () => {
        console.log('%c回调监听，音频已经完成播放', 'color: #2196f3');
        // 播放结束后，停止绘制canavs
        stopDrawPlay();
      };
    } else {
      recorder.stop();
    }

    recorder.start().then(
      () => {
        console.log('开始录音');
        setIsRecording(true);
        // 开始绘制canvas
        setTimeout(() => {
          oCanvas = document.getElementById('canvas');
          ctx = oCanvas.getContext('2d');
          drawRecord();
        }, 100);
      },
      (error: { name: any; message: any }) => {
        console.log(`${error.name}：${error.message}`);
        // toast.error(
        //   `${
        //     getLocale(error.name, locale)
        //       ? getLocale(error.name, locale)
        //       : error.message
        //   }`
        // );
        toast.error(`${error.message}`);
      }
    );
  };

  const startAdornment = (
    <>
      {chatSettings.inputs.length > 0 && (
        <IconButton
          disabled={disabled}
          color="inherit"
          onClick={() => setChatSettings((old) => ({ ...old, open: true }))}
        >
          <TuneIcon />
        </IconButton>
      )}
      <HistoryButton onClick={onHistoryClick} />
    </>
  );

  const clearText = () => {
    setValue('');
  };

  const endAdornment = (
    <>
      {value ? (
        <IconButton color="inherit" onClick={() => clearText()}>
          <HighlightOffOutlinedIcon />
        </IconButton>
      ) : null}
      <IconButton
        disabled={disabled}
        color="inherit"
        onClick={() => startRecordAudio()}
      >
        <KeyboardVoiceIcon />
      </IconButton>
      <IconButton disabled={disabled} color="inherit" onClick={() => submit()}>
        <SendIcon />
      </IconButton>
    </>
  );

  const tranRecordSecToMin = (sec: any) => {
    const minute = Math.floor(sec / 60);
    const rest_seconds = sec % 60;
    setDuration(
      minute.toString().padStart(2, '0') +
        ':' +
        rest_seconds.toString().padStart(2, '0')
    );
  };

  return isRecording ? (
    <div
      style={{
        width: '100%',
        height: 60,
        borderRadius: 5,
        display: 'flex',
        backgroundColor: 'rgb(245 248 255)',
        border: '1px solid #6c72ff',
        boxShadow:
          '0 4px 6px -2px rgba(16,24,40,.03), 0 12px 16px -4px rgba(16,24,40,.08)'
      }}
    >
      <div
        style={{
          height: 60,
          flex: 'none',
          display: 'flex',
          alignItems: 'center',
          paddingLeft: 15,
          color: 'rgb(107 114 128)',
          fontSize: 14,
          fontWeight: 100
        }}
      >
        {tranAudioLoading ? (
          <CircularProgress size={20} sx={{ marginRight: 1 }} />
        ) : null}
        {tranAudioLoading
          ? getLocale('TransformingSpeed', locale)
          : getLocale('NowSpeed', locale)}
      </div>
      <canvas id="canvas" style={{ width: '100%', paddingLeft: 10 }}></canvas>
      <div
        style={{
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'center',
          flex: 1,
          paddingRight: 10,
          paddingLeft: 10
        }}
      >
        {!tranAudioLoading ? (
          <IconButton color="inherit" onClick={() => endRecord()}>
            <StopCircleOutlinedIcon />
          </IconButton>
        ) : null}
        <span
          style={{ fontSize: 14, fontWeight: 100, color: 'rgb(107 114 128)' }}
        >
          {duration}
        </span>
      </div>
    </div>
  ) : (
    <TextField
      inputRef={ref}
      id="chat-input"
      autoFocus
      multiline
      variant="standard"
      autoComplete="false"
      placeholder={getLocale('TypeYourMessageHere', locale)}
      disabled={disabled}
      onChange={(e) => setValue(e.target.value)}
      onKeyDown={handleKeyDown}
      onCompositionStart={handleCompositionStart}
      onCompositionEnd={handleCompositionEnd}
      value={value}
      fullWidth
      InputProps={{
        disableUnderline: true,
        startAdornment: (
          <InputAdornment
            sx={{ ml: 1, color: 'text.secondary' }}
            position="start"
          >
            {startAdornment}
          </InputAdornment>
        ),
        endAdornment: (
          <InputAdornment
            position="end"
            sx={{ mr: 1, color: 'text.secondary' }}
          >
            {endAdornment}
          </InputAdornment>
        )
      }}
      sx={{
        backgroundColor: 'background.paper',
        borderRadius: 1,
        border: (theme) => `1px solid ${theme.palette.divider}`,
        boxShadow: 'box-shadow: 0px 2px 4px 0px #0000000D',

        textarea: {
          height: '34px',
          maxHeight: '30vh',
          overflowY: 'auto !important',
          resize: 'none',
          paddingBottom: '0.75rem',
          paddingTop: '0.75rem',
          color: 'text.primary',
          lineHeight: '24px'
        }
      }}
    />
  );
};

export default Input;
